package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.bloomFilter.BloomFilterConfig;
import com.atguigu.lease.common.bloomFilter.HashStrategy;
import com.atguigu.lease.common.bloomFilter.HashStrategyFactory;
import com.atguigu.lease.common.constant.RedisConstant;
import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.web.admin.custom.bloom.BloomFilterInit;
import com.atguigu.lease.web.admin.mapper.*;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.attr.AttrValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.atguigu.lease.web.admin.vo.room.RoomDetailVo;
import com.atguigu.lease.web.admin.vo.room.RoomItemVo;
import com.atguigu.lease.web.admin.vo.room.RoomQueryVo;
import com.atguigu.lease.web.admin.vo.room.RoomSubmitVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author liubo
 * @description 针对表【room_info(房间信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
public class RoomInfoServiceImpl extends ServiceImpl<RoomInfoMapper, RoomInfo>
        implements RoomInfoService{
@Autowired
private GraphInfoService graphInfoService;
@Autowired
private RoomAttrValueService roomAttrValueService;
@Autowired
private RoomFacilityService roomFacilityService;
@Autowired
private RoomLabelService roomLabelService;
@Autowired
private RoomPaymentTypeService roomPaymentTypeService;
@Autowired
private RoomLeaseTermService roomLeaseTermService;
@Autowired
private RoomInfoMapper roomInfoMapper;
@Autowired
private GraphInfoMapper graphInfoMapper;
@Autowired
private LeaseTermMapper leaseTermMapper;
@Autowired
private FacilityInfoMapper facilityInfoMapper;
@Autowired
private LabelInfoMapper labelInfoMapper;
@Autowired
private PaymentTypeMapper paymentTypeMapper;
@Autowired
private AttrValueMapper attrValueMapper;
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Autowired
private ApartmentInfoMapper apartmentInfoMapper;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void saveOrUpdateByMyself(RoomSubmitVo roomSubmitVo) {

        super.saveOrUpdate(roomSubmitVo);
        boolean isupdate = roomSubmitVo.getId() != null;
        if (isupdate) {
            //删除房间下图片信息
            LambdaQueryWrapper<GraphInfo> graphInfoQueryWrapper = new LambdaQueryWrapper<>();
            graphInfoQueryWrapper.eq(GraphInfo::getItemId, roomSubmitVo.getId());
            graphInfoService.remove(graphInfoQueryWrapper);
            //删除房间下属性信息
            LambdaQueryWrapper<RoomAttrValue> attrValueQueryWrapper = new LambdaQueryWrapper<>();
            attrValueQueryWrapper.eq(RoomAttrValue::getRoomId, roomSubmitVo.getId());
            roomAttrValueService.remove(attrValueQueryWrapper);
            //删除房间下配套信息。
            LambdaQueryWrapper<RoomFacility> roomFacilityWrapper = new LambdaQueryWrapper<>();
            roomFacilityWrapper.eq(RoomFacility::getRoomId, roomSubmitVo.getId());
            roomFacilityService.remove(roomFacilityWrapper);
            //删除房间下标签信息
            LambdaQueryWrapper<RoomLabel> roomLabelWrapper = new LambdaQueryWrapper<>();
            roomLabelWrapper.eq(RoomLabel::getRoomId, roomSubmitVo.getId());
            roomLabelService.remove(roomLabelWrapper);
            //删除房间下支付信息。
            LambdaQueryWrapper<RoomPaymentType> roomPaymentTypeWrapper = new LambdaQueryWrapper<>();
            roomPaymentTypeWrapper.eq(RoomPaymentType::getRoomId, roomSubmitVo.getId());
            roomPaymentTypeService.remove(roomPaymentTypeWrapper);
            //删除房间下可选租期列表
            LambdaQueryWrapper<RoomLeaseTerm> roomLeaseTermWrapper = new LambdaQueryWrapper<>();
            roomLeaseTermWrapper.eq(RoomLeaseTerm::getRoomId, roomSubmitVo.getId());
            roomLeaseTermService.remove(roomLeaseTermWrapper);

            String key = RedisConstant.APP_LOGIN_PREFIX+roomSubmitVo.getId();
            redisTemplate.delete(key);
        }
        //插入图片信息
        List<GraphVo> graphVoList = roomSubmitVo.getGraphVoList();
        if (!CollectionUtils.isEmpty(graphVoList)) {
            List<GraphInfo> graphInfoList = new ArrayList<>();

            for (GraphVo vo : graphVoList) {
                GraphInfo graphInfo = new GraphInfo();
                graphInfo.setItemType(ItemType.ROOM);
                graphInfo.setUrl(vo.getUrl());
                graphInfo.setName(vo.getName());
                graphInfo.setItemId(roomSubmitVo.getId());
                graphInfoList.add(graphInfo);
            }
            graphInfoService.saveBatch(graphInfoList);
        }
        //插入属性信息

        List<Long> longList = roomSubmitVo.getAttrValueIds();
        if (!CollectionUtils.isEmpty(longList)) {
            List<RoomAttrValue> roomAttrValueList = new ArrayList<>();

            for (Long id : longList) {
                RoomAttrValue roomAttrValue = new RoomAttrValue();
                roomAttrValue.setRoomId(roomSubmitVo.getId());
                roomAttrValue.setAttrValueId(id);
                roomAttrValueList.add(roomAttrValue);
            }
            roomAttrValueService.saveBatch(roomAttrValueList);
        }
        //插入配套信息
        List<Long> longList1 = roomSubmitVo.getFacilityInfoIds();
        if (!CollectionUtils.isEmpty(longList1)) {
            List<RoomFacility> roomFacilities = new ArrayList<>();


            for (Long id : longList1) {
                RoomFacility roomFacility = new RoomFacility();
                roomFacility.setFacilityId(id);
                roomFacility.setRoomId(roomSubmitVo.getId());
                roomFacilities.add(roomFacility);
            }
            roomFacilityService.saveBatch(roomFacilities);
        }
        //插入标签信息
        List<Long> labelInfoIds = roomSubmitVo.getLabelInfoIds();
        if (!CollectionUtils.isEmpty(labelInfoIds)) {
            List<RoomLabel> roomLabelList = new ArrayList<>();

            for (Long labelInfoId : labelInfoIds) {
                RoomLabel roomLabel = new RoomLabel();
                roomLabel.setRoomId(roomSubmitVo.getId());
                roomLabel.setLabelId(labelInfoId);
                roomLabelList.add(roomLabel);
            }
            roomLabelService.saveBatch(roomLabelList);
        }
        //插入支付方式信息
        List<Long> paymentTypeIds = roomSubmitVo.getPaymentTypeIds();
        if (!CollectionUtils.isEmpty(paymentTypeIds)) {
            List<RoomPaymentType> roomPaymentTypes = new ArrayList<>();

            for (Long paymentTypeId : paymentTypeIds) {
                RoomPaymentType roomPaymentType = new RoomPaymentType();
                roomPaymentType.setPaymentTypeId(paymentTypeId);
                roomPaymentType.setRoomId(roomSubmitVo.getId());
                roomPaymentTypes.add(roomPaymentType);
            }
            roomPaymentTypeService.saveBatch(roomPaymentTypes);
        }
        //插入租期支付信息
        List<Long> leaseTermIds = roomSubmitVo.getLeaseTermIds();
        if (!CollectionUtils.isEmpty(leaseTermIds)) {
        List<RoomLeaseTerm> roomLeaseTerms = new ArrayList<>();

        for (Long leaseTermId : leaseTermIds) {
            RoomLeaseTerm roomLeaseTerm = new RoomLeaseTerm();
            roomLeaseTerm.setLeaseTermId(leaseTermId);
            roomLeaseTerm.setRoomId(roomSubmitVo.getId());
            roomLeaseTerms.add(roomLeaseTerm);
        }
            BloomFilterConfig bloomFilter = bloomFilterInit.getBloomFilter();
            bloomFilter.add(String.valueOf(roomSubmitVo.getId()));
            roomLeaseTermService.saveBatch(roomLeaseTerms);
    }
    }

    @Override
    public IPage<RoomItemVo> pageSelectRoomItems(IPage<RoomItemVo> page, RoomQueryVo queryVo) {
        return  roomInfoMapper.pageSelectRoomItems(page,queryVo);
    }


    @Autowired
    private BloomFilterInit bloomFilterInit;
    @Override
    public RoomDetailVo getDetailById(Long id) {
        BloomFilterConfig bloomFilter = bloomFilterInit.getBloomFilter();
        if (!bloomFilter.mightContain(String.valueOf(id))) {
            throw new LeaseException(ResultCodeEnum.ADMIN_APARTMENT_NAME_EXIST_ERROR);
        }

        String cacheKey = "room_detail:" + id;
        String lockKey = "lock:room_detail:" + id;

        // 1️⃣ 查询缓存
        RoomDetailVo roomDetailVo = (RoomDetailVo) redisTemplate.opsForValue().get(cacheKey);
        if (roomDetailVo != null) {
            return roomDetailVo;
        }

        // 2️⃣ 使用 Redisson 获取锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 10s 等待时间，30s 过期时间
                try {
                    // 3️⃣ 缓存未命中，二次检查缓存，防止缓存刚被其他线程填充
                    roomDetailVo = (RoomDetailVo) redisTemplate.opsForValue().get(cacheKey);
                    if (roomDetailVo != null) {
                        return roomDetailVo;
                    }

                    // 4️⃣ 查询数据库
                    RoomInfo roomInfo = roomInfoMapper.selectById(id);
                    if (roomInfo == null) {
                        // 防止缓存穿透，缓存空对象 10 分钟
                        redisTemplate.opsForValue().set(cacheKey, new RoomDetailVo(), 10, TimeUnit.MINUTES);
                        return null;
                    }

                    // 5️⃣ 查询相关数据
                    ApartmentInfo apartmentInfo = apartmentInfoMapper.selectById(roomInfo.getApartmentId());
                    List<GraphVo> graphVoList = graphInfoMapper.getDetail(id, ItemType.ROOM);
                    List<FacilityInfo> facilities = facilityInfoMapper.getDetail(id);
                    List<PaymentType> paymentTypes = paymentTypeMapper.getDetail(id);
                    List<LeaseTerm> leaseTerms = leaseTermMapper.getDetail(id);
                    List<AttrValueVo> attrValueList = attrValueMapper.getDetail(id);
                    List<LabelInfo> labelList = labelInfoMapper.getDetail(id);

                    // 6️⃣ 组装数据
                    roomDetailVo = new RoomDetailVo();
                    BeanUtils.copyProperties(roomInfo, roomDetailVo);
                    roomDetailVo.setGraphVoList(graphVoList);
                    roomDetailVo.setFacilityInfoList(facilities);
                    roomDetailVo.setAttrValueVoList(attrValueList);
                    roomDetailVo.setLabelInfoList(labelList);
                    roomDetailVo.setLeaseTermList(leaseTerms);
                    roomDetailVo.setPaymentTypeList(paymentTypes);
                    roomDetailVo.setApartmentInfo(apartmentInfo);

                    // 7️⃣ 写入 Redis，缓存 1 小时
                    redisTemplate.opsForValue().set(cacheKey, roomDetailVo, 1, TimeUnit.HOURS);
                } finally {
                    // 8️⃣ 释放锁
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            } else {
                // 9️⃣ 其他线程未获取到锁，等待 100ms 再重试
                Thread.sleep(100);
                return getDetailById(id);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        }

        return roomDetailVo;
    }



    @Override
    public void removeById_Myself(Long id) {
        super.removeById(id);
        //删除房间下图片信息
        LambdaQueryWrapper<GraphInfo> graphInfoQueryWrapper = new LambdaQueryWrapper<>();
        graphInfoQueryWrapper.eq(GraphInfo::getItemId,id);
        graphInfoService.remove(graphInfoQueryWrapper);
        //删除房间下属性信息
        LambdaQueryWrapper<RoomAttrValue> attrValueQueryWrapper= new LambdaQueryWrapper<>();
        attrValueQueryWrapper.eq(RoomAttrValue::getRoomId,id);
        roomAttrValueService.remove(attrValueQueryWrapper);
        //删除房间下配套信息。
        LambdaQueryWrapper<RoomFacility> roomFacilityWrapper = new LambdaQueryWrapper<>();
        roomFacilityWrapper.eq(RoomFacility::getRoomId,id);
        roomFacilityService.remove(roomFacilityWrapper);
        //删除房间下标签信息
        LambdaQueryWrapper<RoomLabel> roomLabelWrapper = new LambdaQueryWrapper<>();
        roomLabelWrapper.eq(RoomLabel::getRoomId,id);
        roomLabelService.remove(roomLabelWrapper);
        //删除房间下支付信息。
        LambdaQueryWrapper<RoomPaymentType> roomPaymentTypeWrapper = new LambdaQueryWrapper<>();
        roomPaymentTypeWrapper.eq(RoomPaymentType::getRoomId,id);
        roomPaymentTypeService.remove(roomPaymentTypeWrapper);
        //删除房间下可选租期列表
        LambdaQueryWrapper<RoomLeaseTerm> roomLeaseTermWrapper = new LambdaQueryWrapper<>();
        roomLeaseTermWrapper.eq(RoomLeaseTerm::getRoomId,id);
        roomLeaseTermService.remove(roomLeaseTermWrapper);

        String key = RedisConstant.APP_LOGIN_PREFIX+id;
        redisTemplate.delete(key);

    }

    @Override
    public List<String> listAllId() {
        List<String> list = new ArrayList<>();
        roomInfoMapper.selectList(null).forEach(item->{
            list.add(item.getId().toString());
        });
        return list;
    }
}




